<template>
  <div class="text-class-label">
    <a-spin v-show="pageLoading" class="fill-page-loading" @click.stop />
    <label-header
      dmp-label-text="图片分类"
      dmp-label-color="#D61860"
      :title="detailInfo?.name"
      :percent="Number(progressInfo?.progress) || 0"
      @update-success="getTaskDetail()"
    />
    <div class="text-class-label-main">
      <div class="label-layout-main">
        <div class="main-left">
          <img-list
            ref="imgListRef"
            v-model:selected="typeSelected"
            :loading="imgListLoading"
            :current-id="currentImgInfo?.id"
            @selected-text="selectedData"
          />
        </div>
        <div class="main-center">
          <title-bar>
            <template #left>
              <div class="title-bar-left">
                <h4>图片详情</h4>
              </div>
            </template>
            <template #center>
              <div class="title-bar-center flex gap-24">
                <operating-btn
                  title="放大"
                  icon-class="icon-zoom-in-line"
                  :disabled="dmpPaint.zoom >= dmpPaint.maxZoom"
                  @click="zoomCanvasIn"
                />
                <operating-btn
                  title="缩小"
                  icon-class="icon-zoom-out-line"
                  :disabled="dmpPaint.zoom <= dmpPaint.minZoom"
                  @click="zoomCanvasOut"
                />
                <operating-btn title="旋转" icon-class="icon-loop-left-fill" @click="rotate" />
                <operating-btn
                  title="拖拽"
                  icon-class="icon-back_hand"
                  :active="dmpPaint.paintStatus === 'dragCanvas'"
                  @click="changeStatus('dragCanvas')"
                />
                <operating-btn title="重置" icon-class="icon-unzoom-in-line" @click="reset" />
              </div>
            </template>
            <template #right>
              <div class="fbc">
                <div class="shortcut-key-wrap">
                  <a-button
                    v-if="isAllowOperate && currentImgInfo?.type !== 3"
                    type="text"
                    class="flex gap-x-4"
                    :loading="delLoading"
                    @click="toDifficultExample"
                  >
                    <shortcut-key :disabled="!detailInfo" :size="24" title="难例" keys="H" key-name="H" @trigger="toDifficultExample" />
                  </a-button>
                  <a-button
                    v-if="isAllowOperate && currentImgInfo?.type === 3"
                    type="text"
                    class="flex gap-x-4"
                    :loading="recoverLoading"
                    @click="recoverDifficultExample"
                  >
                    撤销难例数据
                  </a-button>

                  <a-button
                    v-if="isAllowOperate && currentImgInfo?.type != 2"
                    type="text"
                    class="flex gap-x-4"
                    :loading="delLoading"
                    @click="toVoid"
                  >
                    <shortcut-key :size="24" title="无效数据" keys="W" key-name="W" @trigger="toVoid" />
                  </a-button>
                  <a-button
                    v-if="isAllowOperate && currentImgInfo?.type === 2"
                    type="text"
                    class="flex gap-x-4"
                    :loading="recoverLoading"
                    @click="recoverVoid"
                  >
                    撤销无效数据
                  </a-button>

                  <a-button v-if="isAllowOperate" type="primary" class="flex gap-x-4" :loading="saveLoading" @click="handleSave">
                    <shortcut-key
                      :disabled="!detailInfo || imgListLoading"
                      :style="{ color: detailInfo ? '#fff' : '' }"
                      :size="24"
                      title="保存"
                      keys="S"
                      key-name="S"
                      @trigger="handleSave"
                    />
                  </a-button>
                </div>
              </div>
            </template>
          </title-bar>
          <div class="main-center-content-wrap">
            <div v-show="!currentImgInfo" class="main-empty">不存在可标注的数据</div>
            <div v-show="currentImgInfo" ref="paintWrapperRef" class="label-text-context my-scrollbar">
              <canvas ref="paintDomRef" width="400" height="200"></canvas>
            </div>
            <div class="label-result-wrap">
              <div class="label-result-title">标注结果</div>
              <div class="label-result my-scrollbar">
                <text-class-label-result :list="labelResultList" @delete="delLabelResult" />
              </div>
            </div>
          </div>
        </div>
        <div class="main-right">
          <label-card
            :task-info="detailInfo"
            type="entity"
            @shortcut-key-trigger="shortcutKeyTrigger"
            @entity-delete="entityDelete"
            @entity-update="entityUpdate"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
  import { message } from 'ant-design-vue'
  import { computed, nextTick, onMounted, provide, ref } from 'vue'
  import { useRequest } from 'vue-request'
  import { useRoute } from 'vue-router'

  import { imgLabelApi } from '@/services/index'
  import { DmpImgBasicPaint, PaintStatus } from '@/utils/dmp-paint'

  import LabelCard from '../../components/LabelCard/index.vue'
  import LabelHeader from '../../components/LabelHeader.vue'
  import TitleBar from '../../components/TitleBar.vue'
  import TextClassLabelResult from '../../dmp-text/components/TextClassLabelResult.vue'
  import { useTagChange, useUniqueLabel } from '../../dmp-text/hooks/useWebSocket'
  import { useProgress, useTask } from '../../hooks/use-task-info'
  import ImgList from '../components/ImgList.vue'
  import OperatingBtn from '../components/OperatingBtn.vue'
  import { ImgTaskItem } from '../types'

  const route = useRoute()
  const pageParams = route.params

  // 任务信息
  const { detailInfo, isEditable, getTaskDetail } = useTask(pageParams?.id as string)
  // 任务进度
  const { progressInfo, getLabelProgress } = useProgress(pageParams?.id as string)
  // 标签变更--连接
  const { connect: tagChangeConnect } = useTagChange()
  // 标注唯一验证--连接
  const { connect: uniqueLabelConnect, send: uniqueLabelSend, isLocked } = useUniqueLabel({ onOpen: () => getCurrentTextInfo })

  // 注入数据
  provide('isEditable', isEditable)

  // 文本筛选
  const imgListRef = ref<InstanceType<typeof ImgList>>()
  const typeSelected = ref<number>(0)
  const labelResultList = ref<any[]>([])
  const imgListLoading = ref(false)
  const currentImgInfo = ref<ImgTaskItem | null>(null)

  const dmpPaint = ref(new DmpImgBasicPaint())
  const paintDomRef = ref<HTMLCanvasElement>()
  const paintWrapperRef = ref<HTMLElement>()

  // 页面全局loading
  const pageLoading = computed(
    () =>
      delLoading.value ||
      recoverLoading.value ||
      toDifficultExampleLoading.value ||
      recoverDifficultExampleLoading.value ||
      imgListLoading.value ||
      saveLoading.value
  )
  // 是否可操作文本详情区域
  const isAllowOperate = computed(() => isEditable.value && currentImgInfo.value && !isLocked.value)

  // 保存
  const { loading: saveLoading, runAsync: runSave } = useRequest<any>(imgLabelApi.save)
  const handleSave = async () => {
    if (pageLoading.value) {
      return
    }
    const labelList = labelResultList.value.map(item => {
      return {
        taskLabelId: item.id,
        taskLabelName: item.name
      }
    })

    const params = {
      taskId: detailInfo.value?.id,
      taskInfoId: currentImgInfo.value?.id,
      resultTypeEnum: 0,
      resultReqVOList: labelList
    }
    const { data } = await runSave(params, {
      isAddUid: true
    })
    message.success('保存成功')
    if (!data) {
      getLabelProgress()
      return
    }
    imgListRef.value?.refreshList()
    getCurrentTextInfo()
  }

  // 选择数据
  const selectedData = (params: any) => {
    if (currentImgInfo.value?.id === params.id) {
      return
    }
    getCurrentTextInfo(params.id)
  }

  // 获取标注结果
  const getLabelResult = async (params: any) => {
    try {
      const { data } = await imgLabelApi.getLabelResult({ taskId: pageParams?.id, taskInfoId: params?.id, resultTypeEnum: 0 })
      labelResultList.value = []
      data?.forEach((item: any) => {
        if (item.type === 0) {
          labelResultList.value.push({
            id: item.taskLabelId,
            name: item.labelName,
            color: item.color
          })
        }
      })
    } catch (error) {}
  }

  // 删除标注结果
  const delLabelResult = (data: any) => {
    labelResultList.value = labelResultList.value.filter(item => item.id !== data.id)
  }

  // 标签快捷键触发
  const shortcutKeyTrigger = async (data: any) => {
    if (labelResultList.value.some(item => item.id === data.id)) {
      message.error('此标签已存在于标注结果中')
      return
    }
    labelResultList.value.unshift({
      id: data?.id,
      name: data?.name,
      color: data?.color
    })
  }

  //标签被删除
  const entityDelete = (data: any) => {
    labelResultList.value = labelResultList.value.filter(item => item.id !== data.id)
    getCurrentTextInfo()
    imgListRef.value?.refreshList()
  }

  // 标签被更新
  const entityUpdate = (data: any) => {
    labelResultList.value = labelResultList.value.map(item => {
      if (item.id === data.id) {
        return {
          ...item,
          name: data.name,
          color: data.color
        }
      }
      return item
    })
  }

  // 获取当前标注任务文本
  const getCurrentTextInfo = async (taskInfoId?: string) => {
    const { data } = await imgLabelApi.getCurrentTextInfo({
      taskId: pageParams?.id,
      taskInfoId,
      markStatusType: typeSelected.value
    })

    uniqueLabelSend({
      lastInfoId: currentImgInfo.value?.id,
      currentInfoId: data?.id || null,
      taskId: pageParams?.id
    })

    /* 重置任务状态 */
    labelResultList.value = []
    currentImgInfo.value = null

    await getLabelProgress()

    if (!data?.id) {
      return
    }

    imgListLoading.value = true
    currentImgInfo.value = data
    initCanvas(currentImgInfo.value)
    try {
      await getLabelResult(data)
    } catch (error) {
    } finally {
      imgListLoading.value = false
    }
  }

  /* 画布操作-------------------------------------------------------------------------------------- */
  const initCanvas = async (data: any) => {
    // 如果已存在则卸载
    if (dmpPaint.value) {
      dmpPaint.value.dispose()
    }
    // 初始化
    dmpPaint.value = new DmpImgBasicPaint()

    await nextTick()
    if (paintDomRef.value && paintWrapperRef.value) {
      paintDomRef.value.width = paintWrapperRef.value.clientWidth
      paintDomRef.value.height = paintWrapperRef.value.clientHeight
      dmpPaint.value.init(paintDomRef.value)
      dmpPaint.value.loadImage(data.fileUrl)
    }
  }
  const changeStatus = (status: PaintStatus) => {
    dmpPaint.value.setStatus(status)
  }
  const zoomCanvasIn = () => {
    dmpPaint.value.zoomCanvasIn()
  }
  const zoomCanvasOut = () => {
    dmpPaint.value.zoomCanvasOut()
  }
  const rotate = () => {
    dmpPaint.value.rotate()
  }
  const reset = () => {
    dmpPaint.value.reset()
  }

  /* 无效和撤销无效------------------------------------------------------------------------------------------------------------------------------------------- */
  const { loading: delLoading, runAsync: runDelText } = useRequest(imgLabelApi.void)
  const { loading: recoverLoading, runAsync: runRecoverText } = useRequest(imgLabelApi.recoverVoid)
  // 撤销无效
  const recoverVoid = async () => {
    if (pageLoading.value) {
      return
    }
    await runRecoverText({}, { urlParams: { id: currentImgInfo?.value?.id }, isAddUid: true })
    getCurrentTextInfo()
    imgListRef.value?.refreshList()
    message.success('撤销成功')
  }

  // 无效
  const toVoid = async () => {
    if (pageLoading.value) {
      return
    }
    await runDelText({}, { urlParams: { id: currentImgInfo?.value?.id }, isAddUid: true })
    getCurrentTextInfo()
    imgListRef.value?.refreshList()
    message.success('操作成功')
  }

  /* 难例和撤销难例------------------------------------------------------------------------------------------------------------------------------------------- */
  const { loading: toDifficultExampleLoading, runAsync: runDifficultExample } = useRequest(imgLabelApi.difficultExample)
  const { loading: recoverDifficultExampleLoading, runAsync: runRecoverDifficultExample } = useRequest(imgLabelApi.recoverDifficultExample)

  // 难例
  const toDifficultExample = async () => {
    if (pageLoading.value) {
      return
    }
    await runDifficultExample({}, { urlParams: { id: currentImgInfo?.value?.id }, isAddUid: true })
    getCurrentTextInfo()
    imgListRef.value?.refreshList()
    message.success('操作成功')
  }
  // 撤销难例
  const recoverDifficultExample = async () => {
    if (pageLoading.value) {
      return
    }
    await runRecoverDifficultExample({}, { urlParams: { id: currentImgInfo?.value?.id }, isAddUid: true })
    getCurrentTextInfo()
    imgListRef.value?.refreshList()
    message.success('撤销成功')
  }

  /* init-------------------------------------------------------------------------------------- */
  const init = () => {
    tagChangeConnect(pageParams.id as string)
    uniqueLabelConnect()
    getTaskDetail()
  }

  init()
</script>

<style lang="less" scoped>
  @import '../../styles/index.less';

  // 整个页面的spin
  .fill-page-loading {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 99999;
    display: flex;
    justify-content: center;
    align-items: center;
    width: 100vw;
    height: 100vh;
    background-color: rgba(255, 255, 255, 0.55);
  }

  .text-class-label {
    width: 100%;
    height: 100%;
    background: #fff;

    .text-class-label-main {
      height: calc(100% - 54px);
    }
  }

  .label-layout-main {
    display: flex;
    width: 100%;
    height: 100%;

    .main-left {
      display: flex;
      width: 240px;
      height: 100%;
      border-right: 1px solid @mask1;
      flex-direction: column;
      flex-shrink: 0;
    }

    .main-center {
      flex: 1;
      height: 100%;
      border-right: 1px solid @mask1;

      .title-bar-left {
        display: flex;
        align-items: center;
        gap: 0 12px;

        > h4 {
          font-size: 14px;
          white-space: nowrap;
          color: @text02;
          font-weight: 700;
        }
      }

      .main-center-content-wrap {
        display: flex;
        width: 100%;
        height: calc(100% - 56px);
        min-height: calc(100vh - 54px - 56px);
        border-top: 1px solid @mask1;

        .main-empty {
          display: flex;
          justify-content: center;
          align-items: center;
          width: 100%;
          height: 100%;
        }

        .label-text-context {
          overflow-y: hidden;
          width: 100%;
          height: 100%;
          font-size: 14px;
          color: @text01;
          font-weight: 400;
          background-color: #f5f5f5;
        }

        .label-result-wrap {
          display: flex;
          width: 180px;
          height: 100%;
          min-height: 0;
          flex-direction: column;

          .label-result-title {
            padding: 12px;
            font-size: 14px;
            color: @text02;
            font-weight: 700;
            line-height: 22px;
          }

          .label-result {
            overflow-y: auto;
            padding: 0 12px 12px;
            width: 180px;
            flex: 1;
            background: #fafafa;

            .tags-wrap {
              display: flex;
              flex-wrap: wrap;
              gap: 12px;
            }
          }
        }
      }
    }

    .main-right {
      width: 320px;
      height: 100%;
      flex-shrink: 0;
    }
  }
</style>
